﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using XMK.Framework.Model;
using System.Data;
using XMK.Utils;
using System.Data.Common;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace XMK.Framework.DataAccess
{
    /// <summary>
    /// 数据操作帮助类
    /// </summary>
    public class DbCmdHelper:IDisposable
    {
        #region 实例化
        /// <summary>
        /// 根据数据库驱动和存储过程名称实例化数据操作帮助类
        /// </summary>
        /// <param name="dbProvider">数据库驱动</param>
        /// <param name="sqlText">存储过程名称</param>
        public DbCmdHelper(DbProvider dbProvider, string sqlText) : this(dbProvider, sqlText, null) { }

        /// <summary>
        /// 根据数据库驱动、存储过程名称和获取参数委托实例化数据操作帮助类
        /// </summary>
        /// <param name="dbProvider">数据库驱动</param>
        /// <param name="sqlText">存储过程名称</param>
        /// <param name="fun">参数委托</param>
        public DbCmdHelper(DbProvider dbProvider, string sqlText, GetDbParamsFun fun)
        {
            this.DbProvider = dbProvider;
            this.DbCmdInfo = new DbCmdInfo(sqlText);
            if (fun != null)
            {
                this.DbCmdInfo.Params.AddRange(
                    ParamCacheHelper.GetCachedParameters(dbProvider.ToString() + sqlText, fun));
            }
        }
        #endregion

        #region 属性
        /// <summary>
        /// 数据库驱动
        /// </summary>
        public DbProvider DbProvider { get; set; }
        /// <summary>
        /// 命令实例
        /// </summary>
        public DbCmdInfo DbCmdInfo { get; set; }
        #endregion

        #region 生成参数
        /// <summary>
        /// 生成指定名称的单个参数
        /// </summary>
        /// <param name="dbProvider">数据库驱动</param>
        /// <param name="paramName">参数名称</param>
        /// <returns></returns>
        public static IDbDataParameter CreateParameter(DbProvider dbProvider, string paramName)
        {
            return dbProvider.CreateParameter(paramName);
        }
        /// <summary>
        /// 生成指定名称和传入传出的参数
        /// </summary>
        /// <param name="dbProvider">数据库类型</param>
        /// <param name="paramName">参数名称</param>
        /// <param name="direction">参数为传入传出</param>
        /// <param name="dbType">参数类型</param>
        /// <returns></returns>
        public static IDbDataParameter CreateParameter(DbProvider dbProvider, string paramName, ParameterDirection direction, DbType dbType)
        {
            return dbProvider.CreateParameter(paramName, direction, dbType);
        }
        /// <summary>
        /// 生成指定名称和类型，并赋值的参数
        /// </summary>
        /// <param name="dbProvider">数据库类型</param>
        /// <param name="paramName">参数名称</param>
        /// <param name="paramValue">参数值</param>
        /// <param name="direction">参数为传入传出</param>
        /// <param name="dbType">参数类型</param>
        /// <param name="size">参数类型大小</param>
        /// <returns></returns>
        public static IDbDataParameter CreateParameter(DbProvider dbProvider, string paramName, object paramValue,
            ParameterDirection direction, DbType dbType, int size)
        {
            IDbDataParameter param = dbProvider.CreateParameter(paramName, direction, dbType);
            param.Size = size;
            param.Value = paramValue;
            return param;
        }
        /// <summary>
        /// 生成指定名称的参数列表
        /// </summary>
        /// <param name="dbProvider">数据库类型</param>
        /// <param name="dbParams">指定的参数名称</param>
        /// <returns></returns>
        public static List<IDbDataParameter> CreateParameters(DbProvider dbProvider, params string[] dbParams)
        {
            return CreateParameters(dbProvider, false, dbParams);
        }
        /// <summary>
        /// 生成指定名称的参数列表
        /// </summary>
        /// <param name="dbProvider">数据库类型</param>
        /// <param name="isPage">是否同时生成分页参数</param>
        /// <param name="dbParams">指定的参数名称</param>
        /// <returns></returns>
        public static List<IDbDataParameter> CreateParameters(DbProvider dbProvider, bool isPage, params string[] dbParams)
        {
            List<IDbDataParameter> list = new List<IDbDataParameter>();
            for (int i = 0; i < dbParams.Length; i++)
            {
                list.Add(dbProvider.CreateParameter(dbParams[i]));
            }
            if (isPage)
                list.AddRange(CreatePageParams(dbProvider));
            return list;
        }
        /// <summary>
        /// 生成排序及分页参数
        /// </summary>
        /// <param name="dbProvider"></param>
        /// <returns></returns>
        private static IDbDataParameter[] CreatePageParams(DbProvider dbProvider)
        {
            return ParamCacheHelper.GetCachedParameters(dbProvider.ToString() + "__page",
                delegate()
                {
                    return new IDbDataParameter[]{
                        dbProvider.CreateParameter("Sort"),
                        dbProvider.CreateParameter("Order"),
                        dbProvider.CreateParameter("CurrentPage"),
                        dbProvider.CreateParameter("PerNum"),
                        dbProvider.CreateParameter("Count", ParameterDirection.Output, DbType.Int32),
                        dbProvider.CreateParameter("PageCount", ParameterDirection.Output, DbType.Int32)
                    };
                });
        }
        #endregion

        #region 参数设值
        /// <summary>
        /// 取得对象的DBNull数据库值
        /// </summary>
        /// <param name="obj">参数信息</param>
        /// <returns>若入参为null，则返回DBNull.Value，否则返回入参</returns>
        public static object ToDBNull(object obj)
        {
            if (obj == null)
                return DBNull.Value;
            return obj;
        }
        /// <summary>
        /// 取得对象的DBNull数据库值或与默认对象一致变成DBNull值
        /// </summary>
        /// <param name="obj">对象</param>
        /// <param name="def">对象的默认值</param>
        /// <returns>若入参为null或者等于def，则返回DBNull.Value，否则返回入参</returns>
        public static object ToDBNull(object obj, object def)
        {
            if (obj == null || obj == def || obj.Equals(def))
                return DBNull.Value;
            return obj;
        }
        /// <summary>
        /// 对参数进行赋值（根据顺序）
        /// </summary>
        /// <param name="paramValues">参数值</param>
        public void SetParamValues(params object[] paramValues)
        {
            for (int i = 0; i < paramValues.Length; i++)
            {
                this.DbCmdInfo.Params[i].Value = ToDBNull(paramValues[i]);
            }
        }
        /// <summary>
        /// 设置排序、分页和其他参数
        /// </summary>
        /// <param name="orderInfo">排序</param>
        /// <param name="pageInfo">分页</param>
        /// <param name="paramValues">参数值</param>
        public void SetParamValues(OrderInfo orderInfo, PageInfo pageInfo, params object[] paramValues)
        {
            this.SetParamValues(paramValues);
            if (orderInfo == null) orderInfo = new OrderInfo();
            int count = this.DbCmdInfo.Params.Count;
            this.DbCmdInfo.Params[count - 6].Value = ParseHelper.Parse<string>(orderInfo.SortSql);
            this.DbCmdInfo.Params[count - 5].Value = ParseHelper.Parse<string>(orderInfo.ColName);
            this.DbCmdInfo.Params[count - 4].Value = ParseHelper.Parse<string>(pageInfo.CurrentPage);
            this.DbCmdInfo.Params[count - 3].Value = ParseHelper.Parse<string>(pageInfo.PageSize);
        }
        #endregion

        #region 取得返回参数
        /// <summary>
        /// 获取返回的分页信息
        /// </summary>
        /// <param name="pageInfo">原始分页</param>
        public void GetReturnPageInfo(PageInfo pageInfo)
        {
            int count = this.DbCmdInfo.Params.Count;
            pageInfo.Records = ParseHelper.Parse<int>(this.DbCmdInfo.Params[count - 2].Value, 0);
            pageInfo.TotalPage = ParseHelper.Parse<int>(this.DbCmdInfo.Params[count - 1].Value, 0);
            if (pageInfo.TotalPage < pageInfo.CurrentPage)
                pageInfo.CurrentPage = pageInfo.TotalPage;
            if (1 > pageInfo.CurrentPage)
                pageInfo.CurrentPage = 1;
        }
        /// <summary>
        /// 获取返回参数信息
        /// </summary>
        /// <param name="param">参数名称</param>
        /// <returns>参数值</returns>
        public object GetReturnOrOutParamValue(string param)
        {
            return this.DbCmdInfo.GetReturnOrOutParamValue(this.DbProvider, param);
        }
        #endregion

        /// <summary>
        /// 清理
        /// </summary>
        public void Dispose()
        {
            this.DbProvider = null;
            this.DbCmdInfo = null;
        }
        /// <summary>
        /// 析构函数
        /// </summary>
        ~DbCmdHelper()
        {
            this.Dispose();
        }
    }
}
